<!-- 单图片上传组件 -->

<!-- 属性 -->
<!-- 配置名称 | 类型 | 用途 | 返回值 | 默认值 | 必填 | 说明 -->
<!-- v-model         | string            | 图片地址        | - | -     | - | 无 -->
<!-- title           | string            | 上传按钮标题     | - | -    | - | 无 -->
<!-- tip             | string            | 上传按钮底部提示 | - | -     | - | 无 -->
<!-- to-ocr          | boolean           | 是否进行ocr识别  | - | false | - | 无 -->
<!-- to-ocr-type      | 1 or 2            | ocr类型         | - | -     | - | 1：企业，2：个人 -->
<!-- disabled        | boolean           | 是否禁用         | - | false | - | 无 -->
<!-- limit-file-size | number            | 文件大小限制     | - | -     | - | 单位MB -->
<!-- mode            | 'light' or 'dark' | 模式            | - | dark   | - | 无 -->
<!-- limit-pixel     | Function          | 像素限制         | - | -     | - | 无 -->
<!-- size            | string            | 图片大小         | - | 96px  | - | 无 -->
<!-- validate-event  | boolean           | 是否触发校验      | - | true  | - | 无 -->

<!-- 事件 -->
<!-- 事件名 | 说明 | Type -->
<!-- image-change | 图片上传成功后触发 | (res?: any) => void -->

<!-- 插槽 -->
<!--
  无
-->

<!-- expose -->
<!-- 方法名 | 说明 | Type -->
<!-- 无 -->
<script setup lang="ts">
import { ElMessage } from 'element-plus'
import { ref, watch } from 'vue'
import { uploadElFile } from '@/utils/uploader'
import { Plus } from '@element-plus/icons-vue'
import BaseImageCard from './widgets/BaseImageCard.vue'
import { getOcrEnterpriseInfo, getOcrIdCardInfo } from '@/api/interface/common/ocr'
import { useFormItem } from 'element-plus'

interface Props {
  title?: string
  tip?: string
  toOcr?: boolean
  toOcrType?: 1 | 2
  disabled?: boolean
  limitFileSize?: number
  mode?: 'light' | 'dark'
  limitPixel?: Function
  size?: string
  validateEvent?: boolean
}

const {
  title,
  tip,
  toOcr = false,
  toOcrType,
  disabled = false,
  limitFileSize,
  mode = 'dark',
  limitPixel,
  size = '96px',
  validateEvent = true
} = defineProps<Props>()

const emit = defineEmits<{
  (e: 'image-change', res?: any): void
}>()

const model = defineModel<string>()

const { formItem } = useFormItem()

const fullscreenLoading = ref(false)

// 初始化样式
const bindBgColor = ref('#ffffff')

const initCSS = () => {
  if (mode === 'dark') {
    bindBgColor.value = 'var(--el-fill-color-lighter)'
  } else {
    bindBgColor.value = '#ffffff'
  }
}
initCSS()

const bindSize = ref(size)

watch(
  () => size,
  (newVal) => {
    if (newVal.includes('px')) {
      bindSize.value = newVal
    } else {
      if (!isNaN(Number(newVal))) {
        bindSize.value = `${newVal}px`
      } else {
        bindSize.value = '96px'
      }
    }
  },
  {
    immediate: true
  }
)

// 获取像素信息
const getPixel = (file: any) => {
  return new Promise((resolve) => {
    if (!file) {
      resolve(null)
    }
    const reader = new FileReader()
    reader.readAsDataURL(file)
    reader.onload = (e: any) => {
      const img = new Image()
      img.src = e.target.result
      img.onload = () => {
        const width = img.width
        const height = img.height
        resolve({
          width,
          height
        })
      }
    }
  })
}

// 上传文件之前
const beforeUpload = async (file: any) => {
  // 如果有限制文件大小传过来
  if (limitFileSize) {
    const isLt1M = file.size / 1024 / 1024 > limitFileSize
    if (isLt1M) {
      ElMessage.error(`上传图片大小不能超过 ${limitFileSize}MB!`)
      return false
    }
  }
  if (limitPixel) {
    const pixel = await getPixel(file)
    if (!pixel) {
      ElMessage.error(`获取图片像素信息失败!`)
      return false
    } else {
      if (!limitPixel(pixel)) {
        ElMessage.error(`上传图片像素不符合要求!`)
        return false
      }
    }
  }
}

// 上传文件
const uploadImg = (params: any) => {
  fullscreenLoading.value = true
  if (!toOcr) {
    uploadElFile(params)
      .then((res: any) => {
        model.value = res.imgUrl
        emit('image-change', res)
        if (validateEvent) {
          formItem?.validate('change')
        }
      })
      .finally(() => {
        fullscreenLoading.value = false
      })
  } else {
    if (toOcrType === 1) {
      // 企业
      getOcrEnterpriseInfo(params.file)
        .then((res: any) => {
          model.value = res.fileInfo.imgUrl
          emit('image-change', res)
          if (validateEvent) {
            formItem?.validate('change')
          }
        })
        .finally(() => {
          fullscreenLoading.value = false
        })
    } else if (toOcrType === 2) {
      // 个人
      getOcrIdCardInfo(params.file)
        .then((res: any) => {
          model.value = res.fileList[0].imgUrl
          emit('image-change', res)
          if (validateEvent) {
            formItem?.validate('change')
          }
        })
        .finally(() => {
          fullscreenLoading.value = false
        })
    } else {
      fullscreenLoading.value = false
    }
  }
}

const imageRemove = () => {
  model.value = void 0
  emit('image-change')
  if (validateEvent) {
    formItem?.validate('change')
  }
}
</script>

<template>
  <div class="base-image-uploader" v-loading.fullscreen.lock="fullscreenLoading">
    <el-upload
      v-if="!model"
      action="#"
      accept="image/jpeg,image/png"
      list-type="picture-card"
      :show-file-list="false"
      :http-request="uploadImg"
      :disabled="disabled"
      :before-upload="beforeUpload"
    >
      <div class="upload-inner">
        <el-icon color="#989A9D" size="16px">
          <Plus />
        </el-icon>
        <div v-if="title" class="upload-inner-title">{{ title }}</div>
      </div>
      <template v-if="tip" #tip>
        <div class="upload-tip">{{ tip }}</div>
      </template>
    </el-upload>
    <div v-else>
      <BaseImageCard :img-url="model" :disabled="disabled" :size="size" @image-remove="imageRemove"></BaseImageCard>
    </div>
  </div>
</template>

<style lang="scss" scoped>
.base-image-uploader {
  display: flex;
  :deep(.el-upload--picture-card) {
    --el-upload-picture-card-size: v-bind(bindSize);
    margin: 0 8px 8px 0;
    border-color: #e3e9f5;
    background-color: v-bind(bindBgColor);
  }
  .upload-inner {
    @include flex(column, center, center);
    margin-top: 12px;
    .upload-inner-title {
      margin-top: 6px;
      font-size: 12px;
      color: #989a9d;
    }
  }
  .upload-tip {
    font-size: 12px;
    color: rgba(154, 154, 156, 0.5);
  }
}
</style>
